/*
 *    Copyright (c) 2018-2025, cloud All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: cloud
 */
package com.fuyao.cloud.asset.budget.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.admin.api.entity.SysDept;
import com.fuyao.cloud.admin.api.entity.SysUser;
import com.fuyao.cloud.admin.api.feign.RemoteDeptService;
import com.fuyao.cloud.admin.api.feign.RemoteUserService;
import com.fuyao.cloud.admin.api.vo.UserVO;
import com.fuyao.cloud.asset.constant.BudgetContant;
import com.fuyao.cloud.asset.contract.mapper.AssetContractMapper;
import com.fuyao.cloud.asset.entity.AssetBudget;
import com.fuyao.cloud.asset.budget.mapper.AssetBudgetMapper;
import com.fuyao.cloud.asset.budget.service.AssetBudgetService;
import com.fuyao.cloud.asset.entity.AssetContract;
import com.fuyao.cloud.asset.vo.BudgetExcelImportVO;
import com.fuyao.cloud.asset.vo.BudgetExcelVO;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.excel.vo.ErrorMessage;
import com.fuyao.cloud.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 预算管理
 *
 * @author 时间的朋友
 * @date 2021-11-12 18:53:46
 */
@Service
@AllArgsConstructor
public class AssetBudgetServiceImpl extends ServiceImpl<AssetBudgetMapper, AssetBudget> implements AssetBudgetService {
    private final RemoteUserService remoteUserService;
    private final RemoteDeptService remoteDeptService;
    private final AssetContractMapper assetContractMapper;

    @Override
    public boolean save(AssetBudget entity) {
        createSave(entity);
        return super.save(entity);
    }

    @Override
    public boolean updateById(AssetBudget entity) {
        createSave(entity);
        return super.updateById(entity);
    }

    /**
     * 保存之前的操作
     *
     * @param entity
     */
    private void createSave(AssetBudget entity) {
        // 开支单位全名称
        if (entity.getExecutionId() != null) {
            R r = remoteDeptService.getById(entity.getExpenditureId());
            SysDept sysDept = (SysDept) r.getData();
            String expenditureFullname = sysDept.getFullName();
            entity.setExpenditureFullname(expenditureFullname);
        }

        // 执行单位全名称
        if (entity.getExecutionId() != null) {
            R r = remoteDeptService.getById(entity.getExecutionId());
            SysDept sysDept = (SysDept) r.getData();
            String executionFullname = sysDept.getFullName();
            entity.setExecutionFullname(executionFullname);
        }
    }

    @Override
    public List<Tree<String>> selectTree() {
        // 查询全部预算
        List<AssetBudget> budgetAllList = baseMapper.selectList(Wrappers.emptyWrapper());
        // 查询数据权限里面的预算
        List<Long> budgetOwnIdList = baseMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope()).stream()
                .map(AssetBudget::getDeptId).collect(Collectors.toList());

        // 权限内部门
        List<TreeNode<String>> collect = budgetAllList.stream()
                .sorted(Comparator.comparing(AssetBudget::getCreateTime)).map(budget -> {
                    TreeNode<String> treeNode = new TreeNode();
                    treeNode.setId(String.valueOf(budget.getYear()));
                    treeNode.setParentId("0");
                    treeNode.setName(String.valueOf(budget.getYear()));
                    treeNode.setWeight(budget.getYear());
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !budgetOwnIdList.contains(budget.getDeptId()));
                    extra.put("createTime", budget.getCreateTime());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());
        // 有权限不返回标识
        return TreeUtil.build(collect, "0");
    }

    @Override
    public List<BudgetExcelVO> listExcel(AssetBudget fyAssetBudget) {
        // 租户id
        fyAssetBudget.setTenantId(SecurityUtils.getUser().getTenantId());
        List<BudgetExcelVO> budgetExcelVOS = this.baseMapper.listExcel(fyAssetBudget);
        for (int i = 0; i < budgetExcelVOS.size(); i++) {
            BudgetExcelVO budgetExcelVO = budgetExcelVOS.get(i);
            budgetExcelVO.setLimitThreshold(budgetExcelVO.getLimitThreshold().equals("1") ? "是" : "否");
            budgetExcelVO.setType(getTypeCost(budgetExcelVO.getType()));
        }
        return budgetExcelVOS;
    }

    private String getTypeCost(String type) {
        switch (type) {
            case BudgetContant.OFICE_CODE:
                return BudgetContant.OFICE_TYPE;
            case BudgetContant.EQUIP_COST_CODE:
                return BudgetContant.EQUIP_COST_TYPE;
            case BudgetContant.RAW_MATERIALS_COST_CODE:
                return BudgetContant.RAW_MATERIALS_COST_TYPE;
            case BudgetContant.MAINTEAN_COST_CODE:
                return BudgetContant.MAINTEAN_COST_TYPE;
            case BudgetContant.COMMISCHARGE_COST_CODE:
                return BudgetContant.COMMISCHARGE_COST_TYPE;
            case BudgetContant.OTHER_COST_CODE:
                return BudgetContant.OTHER_COST_TYPE;
        }
        return "";
    }

    /**
     * excel 导入用户, 插入正确的 错误的提示行号
     *
     * @param excelVOList   excel 列表数据
     * @param bindingResult 错误数据
     * @return ok fail
     */
    @Override
    public R importBudget(List<BudgetExcelImportVO> excelVOList, BindingResult bindingResult) {
        // 通用校验获取失败的数据
        List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
        if (CollUtil.isEmpty(excelVOList) && CollUtil.isEmpty(errorMessageList)) {
            Set<String> errorMsg = new HashSet<>();
            errorMsg.add("无数据导入");
            errorMessageList.add(new ErrorMessage((long) (0 + 2), errorMsg));
        }
        List<SysDept> deptList = remoteDeptService.deptAll().getData();
        // 执行数据插入操作 组装 UserDto
        for (int i = 0; i < excelVOList.size(); i++) {
            Set<String> errorMsg = new HashSet<>();
            BudgetExcelImportVO excel = excelVOList.get(i);
            AssetBudget budget = new AssetBudget();
            SysUser sysUsers = remoteUserService.user(excel.getLiableName()).getData();
            if (sysUsers == null) {
                errorMsg.add("责任人在本系统中不存在");
            } else {
                budget.setLiableId(sysUsers.getUserId());
            }
            Optional<SysDept> optionalSysDept = deptList.stream().filter(sysDept -> sysDept.getFullName().equals(excel.getExpenditureFullname())).findFirst();
            if (!optionalSysDept.isPresent()) {
                errorMsg.add("开支单位在本系统部门中不存在");
            } else {
                SysDept expenditureDept = optionalSysDept.get();
                budget.setExpenditureFullname(expenditureDept.getFullName());
                budget.setExpenditureId(expenditureDept.getDeptId());
            }

            Optional<SysDept> executionFirstOptional = deptList.stream().filter(sysDept -> sysDept.getFullName().equals(excel.getExecutionFullname())).findFirst();
            if (!executionFirstOptional.isPresent()) {
                errorMsg.add("执行单位在本系统部门中不存在");
            } else {
                SysDept executionDept = executionFirstOptional.get();
                budget.setExecutionFullname(executionDept.getFullName());
                budget.setExecutionId(executionDept.getDeptId());
            }
            excel.setLimitThreshold("是".equals(excel.getLimitThreshold()) ? "1" : "0");
            // 数据合法情况 保存
            if (CollUtil.isEmpty(errorMsg)) {
                BeanUtils.copyProperties(excel, budget);
                if(StrUtil.isNotEmpty(excel.getCompletionDate())){
                    budget.setCompletionDate(LocalDateTimeUtil.parseDate(excel.getCompletionDate()));
                }
                boolean saveSucess = super.save(budget);
                if (saveSucess) {
                    errorMsg.add("数据保存失败，请联系管理员");
                }
            } else {
                // 数据不合法情况
                errorMessageList.add(new ErrorMessage((long) (i + 2), errorMsg));
            }
        }
        if (CollUtil.isNotEmpty(errorMessageList)) {
            return R.failed(errorMessageList);
        }
        return R.ok();
    }

    @Override
    public List<Tree<Long>> selectBudgetTree() {
        // 查询全部预算
        List<AssetBudget> budgetAllList = baseMapper.selectList(Wrappers.emptyWrapper());
        // 查询数据权限里面的预算
        List<Long> budgetOwnIdList = baseMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope()).stream()
                .map(AssetBudget::getDeptId).collect(Collectors.toList());

        // 权限内部门
        List<TreeNode<Long>> collect = budgetAllList.stream()
                .sorted(Comparator.comparing(AssetBudget::getCreateTime)).map(budget -> {
                    TreeNode<Long> treeNode = new TreeNode();
                    treeNode.setId(budget.getId());
                    treeNode.setParentId(0L);
                    treeNode.setName(String.valueOf(budget.getNumber()));
                    treeNode.setWeight(120);
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !budgetOwnIdList.contains(budget.getDeptId()));
                    extra.put("createTime", budget.getCreateTime());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());
        return TreeUtil.build(collect, 0L);
    }

    @Override
    public boolean removeById(Serializable id) {
        Long count = assetContractMapper.selectCount(Wrappers.<AssetContract>lambdaQuery().eq(AssetContract::getBudgetId, id));
        Assert.isTrue((count <= 0), "该预算信息关联合同信息，请选删除关联合同信息数据后，再删除预算数据");
        return super.removeById(id);
    }
}
